/***********************************************************************************
 * 文件名： switch_ctrl.c
 * 版本： 2
 * 说明：
 *      switch ctrl （开关量控制器）
 *      提供控制开关量的API: 开、关、闪烁（间断开关）、输出指定PWM值、渐变（PWM值大小变化）。
 *      类似于 sled_ctrl_static 那样操作任意开关量，面向对象设计，可实例化多个对象，单个对象可
 *  控制多个通道，可以用于替代 sled_ctrl_static 和 cled_ctrl_static .
 *      依耐 polsys，且开启用户参数。
 * 修改记录：
 * 	2023/12/09: 初版。 刘言。
 *  2024/07/05: 时间参数单位改为ms。刘言。
***********************************************************************************/
#include "switch_ctrl.h"



// 内部函数声明

static void CtrlLoop(void *obj);
static void NotifyEvent(swc_t *this, swc_ev_t e);
static void SetValueRatio(swc_t *this, u8 vr);

// 对外接口函数

void Swc_Init(swc_t *this, swc_set_value_fun_t fun)
{
    int i;
    memset(this, 0, sizeof(swc_t));
    for(i = 0; i < 3; i++)this->Value[i] = 255;
    this->SetValue = fun;
    Polsys_InitTaskP(&this->SwcTimer, CtrlLoop, this, 10);
}

IN_LINE void Swc_SetCallback(swc_t *this, swc_cb_t callbackfun)
{
    this->Callback = callbackfun;
}

void Swc_SetAction(swc_t *this, swc_action_t action, int time, int count)
{
    this->Action = action;
    this->ActionTime = time / 10;
    this->ActionCount = count;
    if(this->Action != SWC_ACT_NULL)NotifyEvent(this, SWC_EV_ACT_STARTED);
}

IN_LINE void Swc_SetValue(swc_t *this, u8 num, u8 value)
{
    this->Value[num] = value;
}

void Swc_SetColor(swc_t *this, u32 color)
{
    u8 *c = (u8 *)&color;
    u8 i;
    for(i = 0; i < 3; i++)
    {
        this->Value[i] = c[i + 1];
    }
}

IN_LINE swc_action_t Swc_GetAction(swc_t *this)
{
    return this->Action;
}

// 内部函数

static void CtrlLoop(void *obj)
{
	swc_t *this = (swc_t *)obj;
    switch(this->Action)
    {
    case SWC_ACT_ON:
        if (this->ActionTime > 0)
        {
            this->ActionTime--;
            SetValueRatio(this, 255);
        }
        else
        {
            this->Action = SWC_ACT_OFF;
        }
        break;
    case SWC_ACT_OFF:
        SetValueRatio(this, 0);
        this->Action = SWC_ACT_WAIT;
        break;
    case SWC_ACT_FLASH:
        if (this->Time < this->ActionTime)
            SetValueRatio(this, 0);
        else if (this->Time < this->ActionTime * 2)
            SetValueRatio(this, 255);
        else
        {
            this->Time = 0;
            this->ActionCount--;
            if(this->ActionCount == 0)
            {
                this->Action = SWC_ACT_OFF;
            }
        }
        this->Time++;
        break;
    case SWC_ACT_GRA_ON:
        if (this->ActionTime > 0) // 亮的时间
        {
            this->ActionTime--;
            if (this->Count < 255 - this->ActionCount)
                this->Count += this->ActionCount;
            else this->Count = 255;
            SetValueRatio(this, this->Count);
        }
        else
        {
            this->Action = SWC_ACT_GRA_OFF;
        }
        break;
    case SWC_ACT_GRA_OFF:
        if (this->Count > this->ActionCount)
            this->Count -= this->ActionCount;
        else
        {
            this->Action = SWC_ACT_OFF;
            this->Count = 0;
        }
        SetValueRatio(this, this->Count);
        break;
    case SWC_ACT_BREATH:
        if (this->ActionTime > 0)
        {
            this->ActionTime--;
            if (this->Time)
            {
                if (this->Count < 255 - this->ActionCount)
                    this->Count += this->ActionCount;
                else
                {
                    this->Count = 255;
                    this->Time = 0;
                }
            }
            else
            {
                if (this->Count > this->ActionCount)
                    this->Count -= this->ActionCount;
                else
                {
                    this->Count = 0;
                    this->Time = 1;
                }
            }
            SetValueRatio(this, this->Count);
        }
        else
        {
            this->Action = SWC_ACT_GRA_OFF;
        }
        break;
    case SWC_ACT_GRA_COLOR:
        if (this->ActionTime > 0)
        {
            int i;
            this->ActionTime--;
            if (this->Count == 0) //R++
            {
                this->Value[1] = 0;
                this->Value[2] = 0;
                if (this->Value[0] < 255 - this->ActionCount)
                    this->Value[0] += this->ActionCount;
                else
                {
                    this->Value[0] = 255;
                    this->Count = 1;
                }
            }
            else if (this->Count == 1) //步骤1：G++
            {
                if (this->Value[1] < 255 - this->ActionCount)
                    this->Value[1] += this->ActionCount;
                else
                {
                    this->Value[1] = 255;
                    this->Count = 2;
                }
            }
            else if (this->Count == 2) //步骤2：R--
            {
                if (this->Value[0] > this->ActionCount)
                    this->Value[0] -= this->ActionCount;
                else
                {
                    this->Value[0] = 0;
                    this->Count = 3;
                }
            }
            else if (this->Count == 3) //步骤3：B++
            {
                if (this->Value[2] < 255 - this->ActionCount)
                    this->Value[2] += this->ActionCount;
                else
                {
                    this->Value[2] = 255;
                    this->Count = 4;
                }
            }
            else if (this->Count == 4) //步骤4：G--
            {
                if (this->Value[1] > this->ActionCount)
                    this->Value[1] -= this->ActionCount;
                else
                {
                    this->Value[1] = 0;
                    this->Count = 5;
                }
            }
            else if (this->Count == 5) //步骤5：R++
            {
                if (this->Value[0] < 255 - this->ActionCount)
                    this->Value[0] += this->ActionCount;
                else
                {
                    this->Value[0] = 255;
                    this->Count = 6;
                }
            }
            else // 步骤6：B--
            {
                if (this->Value[2] > this->ActionCount)
                    this->Value[2] -= this->ActionCount;
                else
                {
                    this->Value[2] = 0;
                    this->Count = 1;
                }
            }
            for(i = 0; i < 3; i++)this->SetValue(i, this->Value[i]);
        }
        else
        {
            this->Action = SWC_ACT_GRA_OFF;
        }
        break;
    case SWC_ACT_WAIT:
        this->Action = SWC_ACT_NULL;
        NotifyEvent(this, SWC_EV_ACT_NULL);
        break;
    default:
        this->Action = SWC_ACT_NULL;
        this->Count = 0;
        this->Time = 0;
        break;
    }
}

IN_LINE static void NotifyEvent(swc_t *this, swc_ev_t e)
{
    if(this->Callback != NULL)this->Callback(e);
}

/**
 * 设置输出值的比例（亮度）
*/
static void SetValueRatio(swc_t *this, u8 vr)
{
    u8 i;
    u8 value;   // 比例生效后的最终输出值
    for(i = 0; i < 3; i++)
    {
        value = (u16)this->Value[i] * vr / 255;
        this->SetValue(i, value);
    }
}

